import json
from datetime import datetime, date

from django.core.paginator import Paginator, EmptyPage
from django.http import HttpResponseForbidden, HttpResponseNotFound, JsonResponse, HttpResponseServerError
from django.shortcuts import render

# Create your views here.
from django.views import View
from django.views.generic.base import logger

import goods
from goods import constants
from goods.models import GoodsCategory, SKU, GoodsVisitCount
from meiduo_mall.utils.breadcrumb import get_breadcrumb
from meiduo_mall.utils.categories import get_categories
from meiduo_mall.utils.response_code import RETCODE
from django_redis import get_redis_connection


class ListView(View):
    def get(self, request, category_id, page_num=1):
        """提供商品列表页"""

        try:
            category = GoodsCategory.objects.get(pk=category_id)
        except Exception as e:
            return HttpResponseForbidden('分类不存在')

        sort = request.GET.get('sort', 'default')

        if sort == 'default':
            sort_field = '-sales'
        elif sort == 'price':
            sort_field = 'price'
        elif sort == 'hot':
            sort_field = '-comments'
        else:
            sort_field = '-sales'

        skus = SKU.objects.filter(category=category, is_launched=True).order_by(sort_field)

        # 创建分页器：每页N条记录
        paginator = Paginator(skus, constants.GOODS_LIST_LIMIT)

        # 获取每页商品数据
        try:
            page_skus = paginator.page(page_num)
        except EmptyPage:
            # 如果page_num不正确，默认给用户404
            return HttpResponseNotFound('empty page')

        context = {
            'breadcrumb': get_breadcrumb(category),     # 面包屑导航
            'categories': get_categories(),             # 第三级分类
            'page_skus': page_skus,                     # 分页后数据
            'category': category,                       # 第三级分类
            'page_num': page_num,                       # 当前页码
            'total_page': paginator.num_pages,          # 总页码
            'sort': sort,
        }

        return render(request, 'list.html', context)


class HotView(View):
    def get(self, request, category_id):
        # 根据销量倒序
        skus = SKU.objects.filter(category_id=category_id, is_launched=True).order_by('-sales')[:2]

        # 序列化
        hot_skus = []
        for sku in skus:
            hot_skus.append({
                'id': sku.id,
                'default_image_url': sku.default_image.url,
                'name': sku.name,
                'price': sku.price
            })

        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'hot_skus': hot_skus})


class DetailView(View):
    def get(self, request, sku_id):
        """提供商品详情页"""
        # 获取当前sku的信息
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return render(request, '404.html')

        # 查询商品频道分类
        categories = get_categories()
        # 查询面包屑导航
        breadcrumb = get_breadcrumb(sku.category)

        # 构建当前商品的规格键
        sku_specs = sku.specs.order_by('spec_id')
        sku_key = []
        for spec in sku_specs:
            sku_key.append(spec.option.id)
        # 获取当前商品的所有SKU
        skus = sku.spu.skus.all()
        # 构建不同规格参数（选项）的sku字典
        spec_sku_map = {}
        for s in skus:
            # 获取sku的规格参数
            s_specs = s.specs.order_by('spec_id')
            # 用于形成规格参数-sku字典的键
            key = []
            for spec in s_specs:
                key.append(spec.option.id)
            # 向规格参数-sku字典添加记录
            spec_sku_map[tuple(key)] = s.id
        # 获取当前商品的规格信息
        goods_specs = sku.spu.specs.order_by('id')
        # 若当前sku的规格信息不完整，则不再继续
        if len(sku_key) < len(goods_specs):
            return
        for index, spec in enumerate(goods_specs):
            # 复制当前sku的规格键
            key = sku_key[:]
            # 该规格的选项
            spec_options = spec.options.all()
            for option in spec_options:
                # 在规格参数sku字典中查找符合当前规格的sku
                key[index] = option.id
                option.sku_id = spec_sku_map.get(tuple(key), 0) # 如果厂家没生产，黑色+128G的话，匹配不到，给一个默认值0，html里面不生成链接就完了

            spec.spec_options = spec_options

        # 渲染页面
        context = {
            'categories': categories,
            'breadcrumb': breadcrumb,
            'sku': sku,
            'specs': goods_specs,
        }
        return render(request, 'detail.html', context)


class DetailVisitView(View):
    """详情页分类商品访问量"""

    def post(self, request, category_id):
        """记录分类商品访问量"""
        try:
            now_date = date.today()
            gvc = GoodsVisitCount.objects.get(category_id=category_id, date=now_date)
        except:
            GoodsVisitCount.objects.create(
                category_id=category_id,
                count=1
            )
        else:
            gvc.count += 1
            gvc.save()
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})


class HistoryView(View):

    def post(self, request):
        if not request.user.is_authenticated:
            return JsonResponse({'code': RETCODE.USERERR, 'errmsg': '用户没登陆，不缓存浏览记录'})

        tt = json.loads(request.body.decode())
        sku_id = tt.get('sku_id')
        if (not all([sku_id])):
            return JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数错误'})

        count = SKU.objects.filter(id=sku_id).count()
        if count == 0:
            return JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '商品不存在'})

        redis = get_redis_connection('history').pipeline()
        key = 'history:%d' % request.user.id
        redis.lrem(key, 0, sku_id)
        redis.lpush(key, sku_id)
        redis.ltrim(key, 0, 4)
        redis.execute()

        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

    def get(self, request):
        if not request.user.is_authenticated:
            return JsonResponse({'code': RETCODE.USERERR, 'errmsg': '用户没登陆，查询不到浏览历史记录'})

        redis = get_redis_connection('history')
        key = 'history:%d' % request.user.id
        result = redis.lrange(key, 0, -1)

        skus = []
        for id in result:
            sku_id = int(id)
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'default_image_url': sku.default_image.url,
                'name': sku.name,
                'price': sku.price
            })

        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})


